package gobase

import (
	"bytes"
	"crypto/md5"
	"encoding/binary"
	"fmt"
	"io"
	"math"
	"math/rand"
	"regexp"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"time"
	"unicode"
	"unicode/utf8"
	"unsafe"
)

/*
*
字符集	字数	Unicode 编码
基本汉字	20902字	4E00-9FA5  // 一 ~ 龥  (简繁)
基本汉字补充	90字	9FA6-9FFF
扩展A	6592字	3400-4DBF
扩展B	42720字	20000-2A6DF
扩展C	4153字	2A700-2B738
扩展D	222字	2B740-2B81D
扩展E	5762字	2B820-2CEA1
扩展F	7473字	2CEB0-2EBE0
扩展G	4939字	30000-3134A
康熙部首	214字	2F00-2FD5
部首扩展	115字	2E80-2EF3
兼容汉字	477字	F900-FAD9
兼容扩展	542字	2F800-2FA1D
PUA(GBK)部件	81字	E815-E86F
部件扩展	452字	E400-E5E8
PUA增补	207字	E600-E6CF
汉字笔画	36字	31C0-31E3
汉字结构	12字	2FF0-2FFB
汉语注音	43字	3105-312F
注音扩展	22字	31A0-31BA
〇	1字	3007
*/
func IsChineseChar(c rune) bool {
	return c >= 0x4E00 && c <= 0x9FA5
}

/*
*

	包含中文和英文
*/
func ReplaceNonChineseChar(s string, newchr rune) string {
	rs := []rune(s)
	rval := make([]rune, 0, len(rs))
	for _, chr := range rs {
		if IsAsciiPrintChar(chr) || IsChineseChar(chr) {
			rval = append(rval, chr)
		} else {
			rval = append(rval, newchr)
		}
	}
	return string(rval)
}

/*
*

	包含中文和英文
*/
func DelNonChineseChar(s string) string {
	rs := []rune(s)
	rval := make([]rune, 0, len(rs))
	for _, chr := range rs {
		if IsAsciiPrintChar(chr) || IsChineseChar(chr) {
			rval = append(rval, chr)
		}
	}
	return string(rval)
}

func DelNonChineseCharEx(s string, splitchar rune) string {
	idx := 0
	rs := []rune(s)
	rval := make([]rune, 0, len(rs))
	for _, chr := range rs {
		if IsAsciiPrintChar(chr) || IsChineseChar(chr) {
			rval = append(rval, chr)
			idx++
		} else {
			if idx > 0 {
				rval = append(rval, splitchar)
				idx = 0
			}
		}
	}
	return string(rval)
}

func ReplaceNonAsciiChar(s []byte, newchr byte) string {
	rval := make([]byte, 0, len(s))
	for _, chr := range s {
		if IsAsciiPrintByte(chr) {
			rval = append(rval, chr)
		} else {
			rval = append(rval, newchr)
		}
	}
	return string(rval)
}

func DelNonAsciiChar(s []byte) string {
	rval := make([]byte, 0, len(s))
	for _, chr := range s {
		if IsAsciiPrintByte(chr) {
			rval = append(rval, chr)
		}
	}
	return string(rval)
}

func JoinIfNoEmpty(chk string, sep string, args ...string) string {
	if len(chk) == 0 {
		return ""
	} else {
		return strings.Join(args, sep)
	}
}

func DelNonAsciiCharEx(s []byte, splitchar byte) string {
	idx := 0
	rval := make([]byte, 0, len(s))
	for _, chr := range s {
		if IsAsciiPrintByte(chr) {
			rval = append(rval, chr)
			idx++
		} else {
			if idx > 0 {
				rval = append(rval, splitchar)
				idx = 0
			}
		}
	}
	return string(rval)
}

/*
FormatFloatVlst
*/
func FormatFloatVlst(fmtstr string, singalw int, totalwidth int, args ...float64) string {
	strBuf := make([]byte, 0, len(args)*singalw)
	for _, v := range args {
		s0 := AddPrefixForWidth(fmt.Sprintf(fmtstr, v), singalw, " ")
		strBuf = append(strBuf, []byte(s0)...)
	}
	s1 := string(strBuf)
	if totalwidth > 0 {
		s1 = AddSuffixForWidth(s1, totalwidth, " ")
	}
	return s1
}

func ReplaceNonPrintChar(s string, newchr rune) string {
	strs := []rune(s)
	rval := make([]rune, 0, len(strs))
	for _, chr := range strs {
		if unicode.IsPrint(chr) || (chr == 10 || chr == 13 || chr == '\t') {
			rval = append(rval, chr)
		} else {
			rval = append(rval, newchr)
		}
	}
	return string(rval)
}

func DelNonPrintChar(s string) string {
	strs := []rune(s)
	rval := make([]rune, 0, len(strs))
	for _, chr := range strs {
		if unicode.IsPrint(chr) || (chr == 10 || chr == 13 || chr == '\t') {
			rval = append(rval, chr)
		}
	}
	return string(rval)
}

func MD5(str string) string {
	w := md5.New()
	io.WriteString(w, str)
	md5Buf := w.Sum(nil)
	md5str := fmt.Sprintf("%x", md5Buf)
	return md5str
}

func HashStr(str string) int64 {
	var sum int64 = 0
	for i := 0; i < len(str); i++ {
		sum += int64(str[i])
	}
	return sum
}

func MD5Buf(data []byte) string {
	w := md5.New()
	w.Write(data)
	md5str := fmt.Sprintf("%x", w.Sum(nil))
	return md5str
}

// 如果是简单类型请不要使用该函数
// 可以使用GetStrValue函数代替
func ObjectHexAddr(v interface{}) string {
	return fmt.Sprintf("%p", v)
}

/*
*

	StrToNumSuffix("100K", 1024)
	OK:
	  1M, 100K, 1G, 15
	FAIL:
	  1KB, 1.4K 100m15k
*/
func StrToNumSuffix(str string, mult int64) int64 {
	num := int64(1)
	if len(str) > 1 {
		switch str[len(str)-1] {
		case 'G', 'g':
			num *= mult
			fallthrough
		case 'M', 'm':
			num *= mult
			fallthrough
		case 'K', 'k':
			num *= mult
			str = str[0 : len(str)-1]
		}
	}
	parsed, _ := strconv.Atoi(str)
	return int64(parsed) * num
}

/*
**

	HumanSizeToSize("1024KB")
*/
func HumanSizeStrToSize(str string) int64 {
	if len(str) == 0 {
		return 0
	}

	num, suffix := SplitNumericAndRemain(str)
	suffix = Trim(suffix)

	suffix = strings.ToUpper(suffix)

	if suffix == "KB" || suffix == "K" {
		return int64(StrToFloat64Def(num, 0) * 1024)
	}

	if suffix == "MB" || suffix == "M" {
		return int64(StrToFloat64Def(num, 0) * float64(SIZE_MB))
	}

	if suffix == "GB" || suffix == "G" {
		return int64(StrToFloat64Def(num, 0) * float64(SIZE_GB))
	}

	if suffix == "TB" || suffix == "T" {
		return int64(StrToFloat64Def(num, 0) * float64(SIZE_TB))
	}

	return 0
}

/*
**

	00:00-07:00,08:00-10:00,11:00-12:00
*/
func IsInMultiSection(exp, s string) string {
	itms := strings.Split(exp, ",")
	if len(itms) == 1 {
		itms = strings.Split(exp, ";")
	}

	if len(itms) == 1 {
		itms = strings.Split(exp, " ")
	}

	for i := 0; i < len(itms); i++ {
		if IsInSection(itms[i], s) {
			return itms[i]
		}
	}

	return ""
}

/*
**

	00:00-07:00
*/
func IsInSection(exp, s string) bool {
	exp = Trim(exp)
	if len(exp) == 0 {
		return false
	}
	itms := strings.SplitN(exp, "-", 2)
	if len(itms) == 1 {
		itms = strings.SplitN(exp, "~", 2)
	}

	if len(itms) == 1 {
		return false
	}

	return s >= itms[0] && s <= itms[1]
}

func LastChrCnt(s string, c byte) int {
	r := 0
	for i := len(s) - 1; i >= 0; i-- {
		if s[i] == c {
			r++
		} else {
			return r
		}

	}
	return r
}

func shouldEscapeUrl(c byte, mode encoding) bool {
	if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
		return false
	}

	switch c {
	case '%', '?', '&', '+', '=':
		return true
	default:
		if c >= 0 && c <= 31 {
			return true
		}
		return false
	}
}

func urlEncode0(w io.Writer, s string) {
	for i := 0; i < len(s); i++ {
		c := s[i]
		if shouldEscapeUrl(c, 0) {
			w.Write([]byte{'%', upperhex[c>>4], upperhex[c&15]})
		} else {
			w.Write([]byte{c})
		}
	}
}

// 最简单第一个级别的URL编码
func UrlEncode0(s string) string {
	var sb strings.Builder
	urlEncode0(&sb, s)
	return sb.String()
}

// Copy From DxValue.Record
func UnEscapeJSONStr(bvalue []byte) []byte {
	buf := make([]byte, 0, 256)
	blen := len(bvalue)
	i := 0
	unicodeidx := 0
	escapeType := uint8(0) //0 normal,1 json\escapin,2 unicode escape, 3 % url escape
	for i < blen {
		switch escapeType {
		case 1: //json escapin
			escapeType = 0
			switch bvalue[i] {
			case 'a':
				buf = append(buf, '\a')
			case 'b':
				buf = append(buf, '\b')
			case 'f':
				buf = append(buf, '\f')
			case 'n':
				buf = append(buf, '\n')
			case 'r':
				buf = append(buf, '\r')
			case 't':
				buf = append(buf, '\t')
			case 'v':
				buf = append(buf, '\v')
			case '\\':
				buf = append(buf, '\\')
			case '"':
				buf = append(buf, '"')
			case '\'':
				buf = append(buf, '\'')
			case '/':
				buf = append(buf, '/')
			case 'u':
				escapeType = 2 // unicode decode
				unicodeidx = i
			default:
				buf = append(buf, '\\', bvalue[i])
			}
		case 2: //unicode decode
			if (bvalue[i] >= '0' && bvalue[i] <= '9' || bvalue[i] >= 'a' && bvalue[i] <= 'f' ||
				bvalue[i] >= 'A' && bvalue[i] <= 'F') && i-unicodeidx <= 4 {
				//还是正常的Unicode字符，4个字符为一组
				//escapeType = 2
			} else {
				unicodestr := FastByte2String(bvalue[unicodeidx+1 : i])
				if arune, err := strconv.ParseInt(unicodestr, 16, 32); err == nil {
					l := len(buf)
					buf = append(buf, 0, 0, 0, 0)
					runelen := utf8.EncodeRune(buf[l:l+4], rune(arune))
					buf = buf[:l+runelen]
				} else {
					buf = append(buf, bvalue[unicodeidx:i]...)
				}
				escapeType = 0
				continue
			}
		case 3: //url escape
			for j := 0; j < 3; j++ {
				if (bvalue[j+i] >= '0' && bvalue[j+i] <= '9' || bvalue[i+j] >= 'a' && bvalue[i+j] <= 'f' ||
					bvalue[j+i] >= 'A' && bvalue[j+i] <= 'F') && j < 2 {
					//还是正常的Byte字符，2个字符为一组
					//escapeType = 2
				} else {
					bytestr := FastByte2String(bvalue[i : i+j])
					if abyte, err := strconv.ParseInt(bytestr, 16, 32); err == nil {
						buf = append(buf, byte(abyte))
					} else {
						buf = append(buf, bvalue[i-1:i+j]...) //%要加上
					}
					escapeType = 0
					i += j - 1
					break
				}
			}
		default: //normal
			switch bvalue[i] {
			case '\\':
				escapeType = 1 //json escapin
			case '%':
				escapeType = 3 // url escape
			default:
				buf = append(buf, bvalue[i])
			}
		}
		i++
	}
	switch escapeType {
	case 1:
		buf = append(buf, '\\')
	case 2:
		unicodestr := FastByte2String(bvalue[unicodeidx+1 : i])
		if arune, err := strconv.ParseInt(unicodestr, 16, 32); err == nil {
			l := len(buf)
			buf = append(buf, 0, 0, 0, 0)
			runelen := utf8.EncodeRune(buf[l:l+4], rune(arune))
			buf = buf[:l+runelen]
		} else {
			buf = append(buf, bvalue[unicodeidx:i]...)
		}
	}
	return buf
}

func CheckAllStrsIsNotEmpty(strs ...string) bool {
	for i := 0; i < len(strs); i++ {
		if len(strs[i]) == 0 {
			return false
		}
	}
	return true
}

// 解码转义字符，将"\u6821\u56ed\u7f51\t02%20得闲"这类字符串，解码成正常显示的字符串
func ParserJsonEscapeStr(escapedstr string) string {
	return FastByte2String(UnEscapeJSONStr([]byte(escapedstr)))
}

func EscapeSQLStr(str string) string {
	var buf bytes.Buffer
	for _, runedata := range str {
		switch runedata {
		case '\'':
			buf.WriteByte('\'')
			buf.WriteByte('\'')
		case '\\':
			buf.WriteByte('\\')
			buf.WriteByte('\\')
		default:
			buf.WriteRune(runedata)
		}
	}
	return FastByte2String(buf.Bytes())
}

func EscapeStr4Line(str string) string {
	var buf bytes.Buffer
	for _, runedata := range str {
		switch runedata {
		case '\r':
			buf.WriteByte('\\')
			buf.WriteByte('r')
		case '\n':
			buf.WriteByte('\\')
			buf.WriteByte('n')

		default:
			buf.WriteRune(runedata)
		}
	}
	dataBuf := buf.Bytes()
	return *(*string)(unsafe.Pointer(&dataBuf))
}

func UnEscapeStr4Line(str string) string {
	var buf bytes.Buffer
	var escapeflag int8 = 0
	for _, chr := range []byte(str) {
		switch escapeflag {
		case 1:
			escapeflag = 0
			switch chr {
			case 'r':
				buf.WriteByte('\r')
			case 'n':
				buf.WriteByte('\n')
			case 't':
				buf.WriteByte('\t')
			case 'a':
				buf.WriteByte('\a')
			case 'b':
				buf.WriteByte('\b')
			case 'f':
				buf.WriteByte('\f')
			case 'v':
				buf.WriteByte('\v')
			case '\\':
				buf.WriteByte('\\')
			case '"':
				buf.WriteByte('"')
			case '\'':
				buf.WriteByte('\'')
			case '/':
				buf.WriteByte('/')
			default:
				buf.WriteByte(chr)
			}
		default: //normal
			switch chr {
			case '\\':
				escapeflag = 1 //
			default:
				buf.WriteByte(chr)
			}
		}
	}
	dataBuf := buf.Bytes()
	return string(dataBuf)
}

func EscapeJsonStrSimple(str string) string {
	var buf bytes.Buffer
	for _, runedata := range str {
		switch runedata {
		case '\t':
			buf.WriteByte('\\')
			buf.WriteByte('t')
		case '\f':
			buf.WriteByte('\\')
			buf.WriteByte('f')
		case '\r':
			buf.WriteByte('\\')
			buf.WriteByte('r')
		case '\n':
			buf.WriteByte('\\')
			buf.WriteByte('n')
		case '\\':
			buf.WriteByte('\\')
			buf.WriteByte('\\')
		case '"':
			buf.WriteByte('\\')
			buf.WriteByte('"')
		case '\b':
			buf.WriteByte('\\')
			buf.WriteByte('b')
		default:
			buf.WriteRune(runedata)
		}
	}
	return FastByte2String(buf.Bytes())
}

// Copy From DxValue.Record
func EscapeJsonStr(str string) string {
	var buf bytes.Buffer
	for _, runedata := range str {
		switch runedata {
		case '\t':
			buf.WriteByte('\\')
			buf.WriteByte('t')
		case '\f':
			buf.WriteByte('\\')
			buf.WriteByte('f')
		case '\r':
			buf.WriteByte('\\')
			buf.WriteByte('r')
		case '\n':
			buf.WriteByte('\\')
			buf.WriteByte('n')
		case '\\':
			buf.WriteByte('\\')
			buf.WriteByte('\\')
		case '"':
			buf.WriteByte('\\')
			buf.WriteByte('"')
		case '\b':
			buf.WriteByte('\\')
			buf.WriteByte('b')
		default:
			if runedata < 256 {
				buf.WriteByte(byte(runedata))
			} else {
				buf.Write([]byte{'\\', 'u'})
				var b [4]byte
				binary.BigEndian.PutUint32(b[:], uint32(runedata))
				if b[0] == 0 && b[1] == 0 {
					hexstr := Binary2Hex(b[2:])
					buf.WriteString(hexstr)
				} else {
					hexstr := Binary2Hex(b[0:2])
					buf.WriteString(hexstr)
					buf.Write([]byte{'\\', 'u'})
					hexstr = Binary2Hex(b[2:])
					buf.WriteString(hexstr)
				}
			}
		}
	}
	return FastByte2String(buf.Bytes())
}

// 2进制转到16进制
func Binary2Hex(bt []byte) string {
	var bf bytes.Buffer
	vhex := [16]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}
	for _, vb := range bt {
		bf.WriteByte(vhex[vb>>4])
		bf.WriteByte(vhex[vb&0xF])
	}
	return FastByte2String(bf.Bytes())
}

func FastByte2String(bt []byte) string {
	return *(*string)(unsafe.Pointer(&bt))
}

func BufStart(buf []byte, start, l int) []byte {
	return buf[start : start+l]
}

// 预定义十六进制字符映射表（小写）
var hexTable = [16]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}

// BufToHexStr 将字节缓冲区转换为十六进制字符串，支持自定义分隔符
// buf: 输入字节数组
// l: 需要转换的长度（从buf[0]开始）
// spliterstr: 每个字节的十六进制表示之间的分隔符（如空格、":"等）
func BufToHexStr(buf []byte, l int, spliterstr string) string {
	// 处理边界情况
	if l < 0 || len(buf) == 0 || l > len(buf) {
		return ""
	}

	if l == 0 {
		l = len(buf)
	}

	spliter := []byte(spliterstr)
	spliterLen := len(spliter)

	// 计算目标缓冲区大小：每个字节2个十六进制字符 + 分隔符总长度
	totalLen := l * 2
	if spliterLen > 0 && l > 1 {
		totalLen += spliterLen * (l - 1)
	}

	// 预分配精确大小的缓冲区
	dst := make([]byte, 0, totalLen)

	// 处理第一个字节
	dst = append(dst, hexTable[buf[0]>>4], hexTable[buf[0]&0x0f])

	// 处理剩余字节（带分隔符）
	for i := 1; i < l; i++ {
		// 添加分隔符
		if spliterLen > 0 {
			dst = append(dst, spliter...)
		}
		// 添加当前字节的十六进制表示
		dst = append(dst, hexTable[buf[i]>>4], hexTable[buf[i]&0x0f])
	}

	// 直接转换为字符串，避免额外分配
	return *(*string)(unsafe.Pointer(&dst))
}

/*
*
RangeStringSplit("a\r\n汉字b\r\n", "\r\n", func)
*/
func RangeStringSplit(s string, sep string, cb func(idx int, s string) bool) int {
	if len(sep) == 0 {
		cb(0, s)
		return 1
	}
	i := 0
	idx := 0
	for {
		n := strings.Index(s[i:], sep)
		if n == -1 {
			cb(idx, s[i:])
			idx++
			break
		} else {
			ok := cb(idx, s[i:i+n])
			idx++
			i += n + len(sep)
			if !ok || i >= len(s) {
				break
			}
		}
	}

	return idx
}

/*
**

	RangeStringSep("a01;a02", ';', fn);  // 2次
	RangeStringSep("a01", ';', fn);      // 1次
	RangeStringSep("a01;", ';', fn);      // 1次
	RangeStringSep("a01;;", ';', fn);    // 2次
*/
func RangeStringSep(s string, sep rune, cb func(idx int, s1 string) bool) int {
	s1 := []rune(s)
	j := 0
	n := 0
	i := 0
	var ok = true
	for ; i < len(s1); i++ {
		if s1[i] == sep {
			ok = cb(n, string(s1[j:i]))
			n++
			if !ok {
				break
			}
			j = i + 1
		}
	}
	if ok {
		if j < len(s1) {
			cb(n, string(s1[j:]))
			n++
		}
	}

	return n
}

/*
**

	RangeStringSep2("a01;a02", fn, ';', ',');
*/
func RangeStringSep2(s string, cb func(idx int, s1 string) bool, sep0, sep1 rune) int {
	s1 := []rune(s)
	j := 0
	n := 0
	i := 0
	var ok bool
	for ; i < len(s1); i++ {
		if s1[i] == sep0 || s1[i] == sep1 {
			ok = cb(n, string(s1[j:i]))
			n++
			if !ok {
				break
			}
			j = i + 1
		}
	}
	if ok {
		if j < len(s1) {
			cb(n, string(s1[j:]))
			n++
		}
	}

	return n
}

func RangeByteFromHexStr(hexstr string, cb func(v byte) bool) int {
	hexstr = strings.Replace(hexstr, " ", "", -1)
	hexstr = strings.Replace(hexstr, "\r", "", -1)
	hexstr = strings.Replace(hexstr, "\n", "", -1)
	hexstrArr := []rune(hexstr)
	l := len(hexstrArr)

	i := 0

	for {
		if (i + 1) >= l {
			break
		}
		if IsHexChar(hexstrArr[i]) && IsHexChar(hexstrArr[i+1]) {
			v := byte(HexValue(hexstrArr[i])<<4 + HexValue(hexstrArr[i+1]))
			i += 2
			if !cb(v) {
				break
			}
		} else {
			break
		}
	}
	return i / 2

}

func HexStrToBuf(hexstr string) []byte {
	hexstr = strings.Replace(hexstr, " ", "", -1)
	hexstr = strings.Replace(hexstr, "\t", "", -1)
	hexstr = strings.Replace(hexstr, "\r", "", -1)
	hexstr = strings.Replace(hexstr, "\n", "", -1)
	hexstrArr := []rune(hexstr)
	l := len(hexstrArr)
	l2 := l >> 1

	rval := make([]byte, 0, l2)
	i := 0

	for {
		if (i + 1) >= l {
			break
		}
		if IsHexChar(hexstrArr[i]) && IsHexChar(hexstrArr[i+1]) {
			v := HexValue(hexstrArr[i])<<4 + HexValue(hexstrArr[i+1])
			i += 2
			rval = append(rval, byte(v))
		} else {
			break
		}
	}
	return rval

}

func HexValue(chr rune) int {
	c := int(chr)
	if (c >= '0') && (c <= '9') {
		return c - '0'
	} else if c >= 'a' && c <= 'f' {
		return 10 + c - 'a'
	} else {
		return 10 + c - 'A'
	}
}

func HexToInt(hex string) int {
	r := 0
	for _, char := range []rune(hex) {
		r = r<<4 + HexValue(char)
	}
	return r
}

/*
ASCII可显示字符
*/
func IsAsciiPrintByte(c byte) bool {
	return (c >= 32 && c <= 126) || // // 32: (Space), 126:~
		(c == 10 || c == 13 || c == '\t')
}

func IsAsciiPrintChar(chr rune) bool {
	c := byte(chr)
	return (c >= 32 && c <= 126) || // // 32: (Space), 126:~
		(c == 10 || c == 13 || c == '\t')

}

func IsHexChar(chr rune) bool {
	c := byte(chr)
	return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')
}

func Trim(s string) string {
	return strings.Trim(s, " \r\n\t")
}

func CombineIfFirstNotEmpty(s1, s2 string) string {
	if len(s1) > 0 {
		return s1 + s2
	} else {
		return s1
	}
}

func CombineIfNotEmpty(s1, s2 string) string {
	if len(s2) > 0 && len(s1) > 0 {
		return s1 + s2
	} else {
		return ""
	}
}

/*
*

	CutIfMore(txt, 10, "..."))
*/
func CutIfMore(s string, n int, moreflagstr string) string {
	strBuf := []rune(s)
	if len(strBuf) < n {
		return s
	}
	s1 := string(strBuf[:n]) + moreflagstr
	return s1
}

func LeftStr(s string, n int) string {
	strBuf := []rune(s)
	if len(strBuf) < n {
		n = len(strBuf)
	}
	s1 := string(strBuf[:n])
	return s1
}

func CutLeft(s string, n int) (cut string, remain string) {
	strBuf := []rune(s)
	if len(strBuf) < n {
		n = len(strBuf)
	}
	cut = string(strBuf[:n])
	if len(strBuf) > n {
		remain = string(strBuf[n:])
	}
	return
}

/*
*

	The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
*/
func CompareIgnoreCase(s1, s2 string) int {
	s1 = strings.ToLower(s1)
	s2 = strings.ToLower(s2)
	return strings.Compare(s1, s2)
}

/*
**

	idx 从0开始
	"/", "中国/人民", CutPrefixByRune("/中国/人民", 0, 1, "/")
	"/中国/", "人民", CutPrefixByRune("/中国/人民", 1, 1, "/")
*/
func CutPrefixByRune(s string, idx int, cutflag byte, c rune) (cut string, remain string) {
	return CutNPrefixFunc(s, idx, cutflag, func(c1 rune) bool {
		return c1 == c
	})
}

/*
**

	idx 从0开始
	"/人民", "/中国", CutSuffixByRune("/中国/人民", 0, 1, "/")
	"/中国/人民", "", CutSuffixByRune("/中国/人民", 1, 1, "/")
*/
func CutSuffixByRune(s string, idx int, cutflag byte, c rune) (cut string, remain string) {
	return CutNSuffixFunc(s, idx, cutflag, func(c1 rune) bool {
		return c1 == c
	})
}

func CutNPrefixFunc(s string, idx int, cutflag byte, CheckCutBreakFunc func(c rune) bool) (cut string, remain string) {
	i := 0
	return CutPrefixFunc(s, cutflag, func(c rune) bool {
		if CheckCutBreakFunc(c) {
			if i == idx {
				return true
			} else {
				i++
				return false
			}
		} else {
			return false
		}
	})
}

func CutNSuffixFunc(s string, idx int, cutflag byte, CheckCutBreakFunc func(c rune) bool) (cut string, remain string) {
	i := 0
	return CutSuffixFunc(s, cutflag, func(c rune) bool {
		if CheckCutBreakFunc(c) {
			if i == idx {
				return true
			} else {
				i++
				return false
			}
		} else {
			return false
		}
	})
}

/*
*

	    如果CheckCutBreakFunc 一直为false, cut则返回"", remain则返回源字符串
	    返回true表示从该字符进行截断

	    cutflag 0: "中国/人","民"
	    cutflag 1: "中国/人民",""
	    str := "中国/人民";
		plug, remain := CutPrefixFunc(str, 0, func(c rune) bool {
			if c == '民'{
				return true;
			}
			return false;
		})

	    cutflag 0: "中国","/人民"
	    cutflag 1: "中国","/人民"
	    str := "中国/人民";
		plug, remain := CutPrefixFunc(str, 0, func(c rune) bool {
			if c == '/'{
				return true;
			}
			return false;
		})

		fmt.Println(CutPrefixFunc("../abc.txt", 1, func(c rune) bool {
			if c == '.' || c=='/'{
				return false;
			}
			return true;
		}))
	   ../, abc.txt
*/
func CutPrefixFunc(s string, cutflag byte, CheckCutBreakFunc func(c rune) bool) (cut string, remain string) {
	strBuf := []rune(s)
	n := len(strBuf)
	breakn := 0
	cutlist := make([]rune, 0, n)
	for i := 0; i < n; i++ {
		c := strBuf[i]
		if CheckCutBreakFunc(c) {
			if cutflag == 1 {
				cutlist = append(cutlist, c)
				breakn = i + 1
			} else {
				breakn = i
			}
			break
		} else {
			cutlist = append(cutlist, c)
		}
	}
	if breakn == 0 {
		return "", s
	}
	return string(cutlist), string(strBuf[breakn:])
}

/*
**

	如果CheckCutBreakFunc 一直为false, cut则返回"", remain则返回源字符串
*/
func CutSuffixFunc(s string, cutflag byte, CheckCutBreakFunc func(c rune) bool) (cut string, remain string) {
	strBuf := []rune(s)
	n := len(strBuf)
	breakn := n - 1
	for i := n - 1; i >= 0; i-- {
		c := strBuf[i]
		if CheckCutBreakFunc(c) {
			if cutflag == 0 {
				breakn = i + 1
			} else {
				breakn = i
			}
			break
		}
	}
	if breakn == n-1 {
		return "", s
	}
	return string(strBuf[breakn:]), string(strBuf[:breakn])
}

var num2char string = "0123456789ABCDEF"

func TryTrimPrefix(s, prefix string) (newstr string, ok bool) {
	if len(prefix) == 0 {
		return s, false
	}

	if !strings.HasPrefix(s, prefix) {
		return s, false
	}
	return s[len(prefix):], true
}

func TryTrimSuffix(s, suffix string) (newstr string, ok bool) {
	if len(suffix) == 0 {
		return s, false
	}
	if !strings.HasSuffix(s, suffix) {
		return s, false
	}
	return s[:len(s)-len(suffix)], true
}

// depre
func CheckTrimPrefix(s, prefix string) (bool, string) {
	if len(prefix) == 0 {
		return true, s
	}

	if !strings.HasPrefix(s, prefix) {
		return false, s
	}
	return true, s[len(prefix):]
}

func CheckTrimSuffix(s, suffix string) (bool, string) {
	if len(suffix) == 0 {
		return true, s
	}
	if !strings.HasSuffix(s, suffix) {
		return false, s
	}
	return true, s[:len(s)-len(suffix)]
}

func CheckAddPrefix(s, prefix string) (added bool, rval string) {
	if strings.HasPrefix(s, prefix) {
		return false, s
	}
	return true, prefix + s
}

func CheckAddSuffix(s, suffix string) (added bool, rval string) {
	if strings.HasSuffix(s, suffix) {
		return false, s
	}
	return true, s + suffix
}

func CheckAddQuoteChr(s string, prefix, suffix rune) string {
	runelst := []rune(s)
	l := len(runelst)
	if l >= 2 && runelst[0] == prefix || runelst[l-1] == suffix {
		return s
	}

	newlst := make([]rune, 0, l+2)
	newlst = append(newlst, prefix)
	newlst = append(newlst, runelst...)
	newlst = append(newlst, suffix)
	return string(newlst)
}

func Str2lst(s string, sep string, itmprefix, itmsuffix rune, tolower, emptyignore bool) []string {
	if len(s) == 0 {
		return nil
	}
	lst := strings.Split(s, sep)
	if itmprefix == 0 && itmsuffix == 0 && !tolower && !emptyignore {
		return lst
	}

	for i := 0; i < len(lst); i++ {
		s := Trim(lst[i])
		if len(s) == 0 && emptyignore {
			continue
		}

		if tolower {
			s = strings.ToLower(s)
		}
		if itmprefix != 0 && itmsuffix != 0 {
			s = CheckAddQuoteChr(s, itmprefix, itmsuffix)
		}
		lst[i] = s

	}
	return lst
}

//	截掉前后字符
//
// Deprecated: TryTrimQuoteChr
func CheckTrimQuoteChr(s string, prefix, suffix byte) (bool, string) {
	l := len(s)
	if l <= 2 || s[0] != prefix || s[l-1] != suffix {
		return false, s
	}

	return true, s[1 : l-1]
}

// 截掉前后字符
func TryTrimQuoteChr(s string, prefix, suffix byte) (string, bool) {
	l := len(s)
	if l <= 2 || s[0] != prefix || s[l-1] != suffix {
		return s, false
	}

	return s[1 : l-1], true
}

func TryTrimQuoteString(s string, prefix, suffix string) (string, bool) {
	l := len(s)
	if l <= len(prefix)+len(suffix) || s[0:len(prefix)] != prefix || s[l-len(suffix):] != suffix {
		return s, false
	}

	return s[len(prefix) : l-len(suffix)], true
}

// 截掉前后字符串
// Deprecated: TryTrimQuoteString
func CheckTrimQuoteString(s string, prefix, suffix string) (bool, string) {
	l := len(s)
	if l <= len(prefix)+len(suffix) || s[0:len(prefix)] != prefix || s[l-len(suffix):] != suffix {
		return false, s
	}

	return true, s[len(prefix) : l-len(suffix)]
}

func init() {
	rand.Seed(time.Now().UnixNano())
}

var (
	// 使用下面的r, 并发会有异常
	// r *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))

	hex_strs    = "0123456789ABCDEF"
	key_strs    = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	pass_0_strs = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
	num_strs    = "0123456789"
	num2_strs   = "012356789"
)

// 60个纤程同时进行测试没有异常
func RandHexString(len int) string {
	bytes := make([]byte, len)
	for i := 0; i < len; i++ {
		b := rand.Intn(16)
		bytes[i] = byte(hex_strs[b])
	}
	return string(bytes)
}

func RandFloat64(f float64) float64 {
	return f * float64(rand.Intn(100)) / 100.00
}

/*
*

	比较耗cpu
*/
func RandBuf(len int) []byte {
	bytes := make([]byte, len)
	for i := 0; i < len; i++ {
		b := rand.Intn(255)
		bytes[i] = byte(b)
	}
	return bytes
}

func RandNumString(len int) string {
	bytes := make([]byte, len)
	for i := 0; i < len; i++ {
		b := rand.Intn(9)
		bytes[i] = byte(num_strs[b])
	}
	return string(bytes)
}

func RandNumStringWithout4(len int) string {
	bytes := make([]byte, len)
	for i := 0; i < len; i++ {
		b := rand.Intn(8)
		bytes[i] = byte(num2_strs[b])
	}
	return string(bytes)
}

func StrNextSerialNo(str string, maxl int, inc int) string {
	strn := GetLastNumStr(str, maxl)
	if len(strn) == 0 {
		return str + fmt.Sprintf("%.2d", inc)
	}
	strprefix := str[:len(str)-len(strn)]
	fmtstr := "%." + fmt.Sprintf("%d", len(strn)) + "d"
	nextv, err := strconv.ParseInt(strn, 10, 32)
	if err != nil {
		nextv = int64(inc)
	} else {
		nextv += int64(inc)
	}
	strn = fmt.Sprintf(fmtstr, nextv)
	strv := strprefix + strn
	return strv
}

func GetLastNumStr(str string, maxl int) string {
	rval := ""
	j := 0
	for i := len(str) - 1; i >= 0; i-- {
		if str[i] >= '0' && str[i] <= '9' {
			rval = string(str[i]) + rval
			j++
			if j >= maxl {
				break
			}
		} else {
			break
		}
	}
	return rval
}

// 60个纤程同时进行测试没有异常
func RandKeyString(len int) string {
	bytes := make([]byte, len)
	for i := 0; i < len; i++ {
		b := rand.Intn(37 - 1)
		bytes[i] = byte(key_strs[b])
	}
	return string(bytes)
}

func RandPass0String(len int) string {
	bytes := make([]byte, len)
	for i := 0; i < len; i++ {
		b := rand.Intn(62 - 1)
		bytes[i] = byte(pass_0_strs[b])
	}
	return string(bytes)
}

// inttohex
// DecimalToAny(113, 16, 2) = 71
func DecimalToAny(num, n, count int) string {

	new_num_str := ""
	var remainder int
	var remainder_string string
	for num != 0 {
		remainder = num % n
		remainder_string = string(num2char[remainder])
		new_num_str = remainder_string + new_num_str //注意顺序
		num = num / n
	}
	length := len(new_num_str)
	if length == count {
		return new_num_str
	}

	if length < count { //如果小于8位
		for i := 1; i <= count-length; i++ {
			new_num_str = "0" + new_num_str
		}
		return new_num_str
	} else {
		return "ERROR"
	}
}

func AddSuffixForWidth(src string, width int, suffix string) string {
	disl := width - len(src)
	if disl < 0 {
		return src
	}
	fixl := len(suffix)
	if fixl == 0 {
		suffix = " "
		fixl = 1
	}

	if fixl == 1 {
		rep := bytes.Repeat([]byte(suffix), disl)
		str := src + string(rep)
		return str
	} else {
		l := int(math.Ceil(float64(disl) / float64(fixl)))
		rep := bytes.Repeat([]byte(suffix), l)
		str := src + string(rep[:disl])
		return str
	}

}

func AddPrefixForWidth(src string, width int, prefix string) string {
	disl := width - len(src)
	if disl <= 0 {
		return src
	}
	fixl := len(prefix)
	if fixl == 0 {
		prefix = " "
		fixl = 1
	}

	if fixl == 1 {
		rep := bytes.Repeat([]byte(prefix), disl)
		str := string(rep) + src
		return str
	} else {
		l := int(math.Ceil(float64(disl) / float64(fixl)))
		rep := bytes.Repeat([]byte(prefix), l)
		str := string(rep[:disl]) + src
		return str
	}
}

func SplitWidth(s string, fn func(s0 string) (s1 string, ok bool, breakFlag bool), widthlst ...int) (strs []string) {
	startIdx := 0
	strs = make([]string, 0, len(widthlst))
	var ok, breakFlag bool
	for i := 0; i < len(widthlst); i++ {
		s0 := s[startIdx : startIdx+widthlst[i]]
		s0, ok, breakFlag = fn(s0)
		if ok {
			strs = append(strs, s0)
			startIdx += widthlst[i]
		}
		if breakFlag {
			break
		}
	}
	return
}

func SplitWidthTrim(s string, widthlst ...int) (strs []string) {
	startIdx := 0
	strs = make([]string, 0, len(widthlst))
	for i := 0; i < len(widthlst); i++ {
		s0 := s[startIdx : startIdx+widthlst[i]]
		s0 = Trim(s0)
		strs = append(strs, s0)
		startIdx += widthlst[i]
	}
	return
}

func Split2StrV1(s string, sep byte) (s1, s2 string) {
	if len(s) == 0 {
		return
	}

	idx := bytes.IndexByte([]byte(s), sep)
	if idx == -1 {
		s1 = s
		return
	}
	s1 = s[:idx]
	s2 = s[idx+1:]
	return
}

func Split2Str(s, sep string) (s1, s2 string) {
	if len(s) == 0 {
		return
	}
	idx := strings.Index(s, sep)
	if idx == -1 {
		return s, ""
	}
	return s[:idx], s[idx+len(sep):]
}

func LastSplit2Str(s, sep string) (s1, s2 string) {
	if len(s) == 0 {
		return
	}
	idx := strings.LastIndex(s, sep)
	if idx == -1 {
		return s, ""
	}
	return s[:idx], s[idx+len(sep):]
}

//func Split2Str(s, sep string) (s1, s2 string) {
//	if len(s) == 0 {
//		return
//	}
//	strs := strings.SplitN(s, sep, 2)
//	s1 = strs[0]
//	if len(strs) > 1 {
//		s2 = strs[1]
//	}
//	return
//}

func Split3Str(s, sep string) (s1, s2, s3 string) {
	if len(s) == 0 {
		return
	}
	strs := strings.SplitN(s, sep, 3)
	s1 = strs[0]
	if len(strs) > 1 {
		s2 = strs[1]
	}
	if len(strs) > 2 {
		s3 = strs[2]
	}
	return
}

func SplitNumericAndRemain(str string) (numstr, remain string) {
	if len(str) == 0 {
		return
	}

	dotn := 0
	numstr, remain = CutPrefixFunc(str, 0, func(c rune) bool {
		if c >= '0' && c <= '9' {
			return false
		}
		if c == '.' {
			dotn++
			if dotn == 1 {
				return false
			}
		}

		return true
	})
	return
}

func StrToFloat32Def(s string, defval float32) float32 {
	v, err := strconv.ParseFloat(s, 32)
	if err != nil {
		return defval
	} else {
		return float32(v)
	}
}

func StrToFloat64Def(s string, defval float64) float64 {
	v, err := strconv.ParseFloat(s, 64)
	if err != nil {
		return defval
	} else {
		return float64(v)
	}
}

/*
**

	1 = "1"
	0.1 = "0.1"
*/
func Float64ToStr(val float64) string {
	str := strconv.FormatFloat(val, 'f', -1, 64)
	return str
}

func Float32ToStr(val float64) string {
	str := strconv.FormatFloat(val, 'f', -1, 32)
	return str
}

func IsAsciiPrintStr(src string) bool {
	strArr := []rune(src)
	l := len(strArr)

	for i := 0; i < l; i++ {
		if !IsAsciiPrintChar(strArr[i]) {
			return false
		}
	}
	return true
}

func CheckGetStrlist(strs []string, idx int, def string) string {
	if len(strs) > idx {
		return strs[idx]
	} else {
		return def
	}
}

func CheckGetValInlst(lst []interface{}, idx int, def interface{}) interface{} {
	if len(lst) > idx {
		return lst[idx]
	} else {
		return def
	}
}

func IsPrintStrBuf(src []byte) bool {
	return IsPrintStr(string(src))
}

func IsPrintStr(src string) bool {
	if len(src) == 0 {
		return true
	}
	strArr := []rune(src)
	l := len(strArr)
	if l == 0 {
		return false
	}

	for i := 0; i < l; i++ {
		chr := strArr[i]
		if unicode.IsPrint(chr) || strArr[i] == '\r' || strArr[i] == '\n' || strArr[i] == '\t' {
			continue
		} else {
			return false
		}
	}
	return true
}

/*
*

	0:无BOM
	1:UTF8
*/
func DetectBOMType(data []byte) int {
	if len(data) >= 3 {
		if data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF {
			return 1
		}
	}
	return 0
}

/*
*

	GB2312标准共收录6763个汉字，其中一级汉字3755个，二级汉字3008个；
	GBK共收入21886个汉字和图形符号。
	GBK: 8140至FEFE
*/
func HaveAnyGBK(data []byte) bool {
	length := len(data)
	var i int = 0
	for i < length {
		if data[i] <= 0x7f { //  编码0~127,只有一个字节的编码，兼容ASCII码
			i++
			continue
		} else {
			//大于127的使用双字节编码，落在gbk编码范围内的字符
			if i+1 < length && (data[i] >= 0x81 && data[i+1] >= 0x40 && data[i] <= 0xfe && data[i+1] <= 0xfe && data[i+1] != 0xf7) {
				i += 2
				return true
			} else { // 非GBK
				continue
				// return false
			}
		}
	}
	return false
}

/*
*
src 长度必须是2的倍数, 必须都是HEX字符, 不能包含空格
*/
func IsHexStr(src string) bool {
	strArr := []rune(src)
	l := len(strArr)
	if l%2 != 0 {
		return false
	}

	for i := 0; i < l; i++ {
		if !IsHexChar(strArr[i]) {
			return false
		}
	}
	return true
}

func StringsRangeFunc(strs []string, cb func(idx int64, elestr string) bool) (int64, error) {
	index := int64(0)
	for i := 0; i < len(strs); i++ {
		if !cb(int64(i), strs[i]) {
			break
		}
		index++
	}
	return index, nil
}

/*
**

	删除符合条件的元素
*/
func DeleteStrlstEle(strs []string, fn func(s string) bool) []string {
	for i := len(strs) - 1; i >= 0; i-- {
		if fn(strs[i]) {
			strs = append(strs[:i], strs[i+1:]...)
		}
	}
	return strs
}

func StrIndex(s string, strlst ...string) int {
	for i := 0; i < len(strlst); i++ {
		if s == strlst[i] {
			return i
		}
	}
	return -1
}

func StrIndexIgnoreCase(s string, strlst ...string) int {
	for i := 0; i < len(strlst); i++ {
		if strings.ToLower(s) == strings.ToLower(strlst[i]) {
			return i
		}
	}
	return -1
}

/*
*

	1个月  1, 个月
	1 天   1，天
*/
func SplitQuantifiersUnits(s string) (qua string, unit string) {
	runelst := []rune(Trim(s))
	for i := 0; i < len(runelst); i++ {
		chr := runelst[i]
		if chr >= '0' && chr <= '9' {
			continue
		} else if chr == '-' || chr == '+' {
			continue
		} else if chr == '.' {
			continue
		}
		if chr == ' ' || chr == '\t' || chr == '\n' {
			qua = string(runelst[:i])
			unit = string(runelst[i+1:])
			break
		} else {
			qua = string(runelst[:i])
			unit = string(runelst[i:])
			break
		}
	}
	if len(qua) == 0 && len(unit) == 0 {
		qua = s
	}
	return
}

/*
1.将切片 b 的元素追加到切片 a 之后：a = append(a, b...)

2.复制切片 a 的元素到新的切片 b 上：

  b = make([]T, len(a))
  copy(b, a)

3.删除位于索引 i 的元素：a = append(a[:i], a[i+1:]...)

4.切除切片 a 中从索引 i 至 j 位置的元素：a = append(a[:i], a[j:]...)

5.为切片 a 扩展 j 个元素长度：a = append(a, make([]T, j)...)

6.在索引 i 的位置插入元素 x：a = append(a[:i], append([]T{x}, a[i:]...)...)

7.在索引 i 的位置插入长度为 j 的新切片：a = append(a[:i], append(make([]T, j), a[i:]...)...)

8.在索引 i 的位置插入切片 b 的所有元素：a = append(a[:i], append(b, a[i:]...)...)

9.取出位于切片 a 最末尾的元素 x：x, a = a[len(a)-1], a[:len(a)-1]
*/

// 合并多个集合, 返回数组无序, 根据sets进行添加
// BenchmarkMergeSets2-8   	  537085	      2150 ns/op
func MergeSets2[T comparable](sets ...[]T) []T {
	m := make(map[T]struct{})
	var result []T

	for _, s := range sets {
		for _, v := range s {
			if _, ok := m[v]; !ok {
				m[v] = struct{}{}
				result = append(result, v)
			}
		}
	}
	return result
}

// 合并多个集合, 返回数组无序, 根据sets进行添加, 比MergeSets2稍快
// BenchmarkMergeSets2-8   	  628402	      1915 ns/op
func MergeSets[T comparable](sets ...[]T) []T {
	m := make(map[T]struct{})
	var result []T

	for _, s := range sets {
		if len(result) == 0 && len(s) > 0 {
			result = s
			for idx, v := range s {
				if _, ok := m[v]; !ok {
					m[v] = struct{}{}
				} else {
					//a = append(a[:i], a[i+1:]...)
					result = append(result[:idx], result[idx+1:]...)
				}
			}
		} else {
			for _, v := range s {
				if _, ok := m[v]; !ok {
					m[v] = struct{}{}
					result = append(result, v)
				}
			}
		}

	}
	return result
}

// 分割成float64列表
func StrToFloatList(str string, sep string, def float64) (flst []float64) {
	strs := strings.Split(str, sep)
	for i := 0; i < len(strs); i++ {
		s := strs[i]
		flst = append(flst, StrToFloat64Def(s, def))
	}
	return
}

// 分割成float64列表[3]
func StrTo3FloatList(str string, sep string, def float64) (flst [3]float64) {
	strs := strings.SplitN(str, sep, 4)
	for i := 0; i < len(strs) && i < 3; i++ {
		flst[i] = StrToFloat64Def(strs[i], def)
	}
	return
}

func StrTo3Float64(str string, sep string) (f1, f2, f3 float64) {
	strs := strings.SplitN(str, sep, 4)
	if len(strs) >= 1 {
		f1 = StrToFloat64Def(Trim(strs[0]), 0)
		if len(strs) >= 2 {
			f2 = StrToFloat64Def(Trim(strs[1]), 0)
			if len(strs) >= 3 {
				f3 = StrToFloat64Def(Trim(strs[2]), 0)
			}
		}
	}
	return
}

func StrToInts(str string, sep string) (rval []int) {
	strs := strings.Split(str, sep)
	rval = make([]int, 0, len(strs))
	for i := 0; i < len(strs); i++ {
		s := Trim(strs[i])
		if len(s) > 0 {
			v, err := strconv.ParseInt(s, 10, 64)
			if err == nil {
				rval = append(rval, int(v))
			}
		}
	}
	return
}

func StrToUInt8List(str string, sep string) (rval []byte) {
	strs := strings.Split(str, sep)
	rval = make([]byte, 0, len(strs))
	for i := 0; i < len(strs); i++ {
		s := Trim(strs[i])
		if len(s) > 0 {
			v, err := strconv.ParseInt(s, 10, 64)
			if err == nil {
				rval = append(rval, byte(v))
			}
		}
	}
	return
}

func Int8ListToStrs(lst []int8, sep string) string {
	var bb strings.Builder
	for i := 0; i < len(lst); i++ {
		if bb.Len() > 0 {
			bb.WriteString(sep)
		}
		bb.WriteString(fmt.Sprintf("%d", lst[i]))
	}
	return bb.String()
}

func StrToInt8List(str string, sep string) (rval []int8) {
	strs := strings.Split(str, sep)
	rval = make([]int8, 0, len(strs))
	for i := 0; i < len(strs); i++ {
		s := Trim(strs[i])
		if len(s) > 0 {
			v, err := strconv.ParseInt(s, 10, 64)
			if err == nil {
				rval = append(rval, int8(v))
			}
		}
	}
	return
}

func UInt8ListToStrs(lst []byte, sep string) string {
	var bb strings.Builder
	for i := 0; i < len(lst); i++ {
		if bb.Len() > 0 {
			bb.WriteString(sep)
		}
		bb.WriteString(fmt.Sprintf("%d", lst[i]))
	}
	return bb.String()
}

func StrToIntDef(s string, defval int) int {
	v, err := strconv.ParseInt(s, 10, 64)
	if err != nil {
		return defval
	} else {
		return int(v)
	}
}

func StrToInt8Def(s string, defval int8) int8 {
	return int8(StrToInt64Def(s, int64(defval)))
}

func StrToUint64Def(s string, defval uint64) uint64 {
	v, err := strconv.ParseUint(s, 10, 64)
	if err != nil {
		if strings.HasPrefix(s, "0x") {
			v, err := strconv.ParseUint(s[2:], 16, 64)
			if err != nil {
				return defval
			} else {
				return v
			}
		}
		return defval
	} else {
		return v
	}
}

func StrToInt64Def(s string, defval int64) int64 {
	v, err := strconv.ParseInt(s, 10, 64)
	if err != nil {
		if strings.HasPrefix(s, "0x") {
			v, err := strconv.ParseInt(s[2:], 16, 64)
			if err != nil {
				return defval
			} else {
				return v
			}
		}
		return defval
	} else {
		return int64(v)
	}
}

func ReplaceReg(s string, regP string, new string) (string, error) {
	reg, err := regexp.Compile(regP)
	if err != nil {
		return "", err
	}

	return string(reg.ReplaceAll([]byte(s), []byte(new))), nil
}

/*
*

	s := "a    b    c     d    " -> "a b c d "
*/
func ReplaceMultiSpace2One(s string, new string) string {
	str, err := ReplaceReg(s, "( )+", new)
	if err != nil {
		return s
	}
	return str
}

/*
*

	ReplaceMultiAny2One("a    b    c     d    ", " ", ":");   -> "a:b:c:d:"
	ReplaceMultiAny2One("a    b    c     d    "," "," ")->"a b c d "
	ReplaceMultiAny2One("ababaaa aab ac d aaa ","ab","x")->"xaaa ax ac d aaa "
	ReplaceMultiAny2One("aaaaa aab ac d aaa ", "aa", "x")->"xa xb ac d xa"
*/
func ReplaceMultiAny2One(s string, any, new string) string {
	regP := fmt.Sprintf("(%s)+", regexp.QuoteMeta(any))
	//fmt.Println(regP)
	str, err := ReplaceReg(s, regP, new)
	if err != nil {
		return s
	}
	return str
}

/*
*
忽略大小写

	`<td>a</td><td>b</td>`
	ReplaceArea(str, "<td>", "</td>", "<td>abc</td>") = <td>abc</td><td>abc</td>
*/
func ReplaceArea(s string, start, end string, new string) string {
	// regexp.MustCompile(`(?i:^hello).*Go`)
	strRegFind := fmt.Sprintf("(?i:%s)[\\s\\S]*?(?i:%s)",
		regexp.QuoteMeta(start), regexp.QuoteMeta(end))

	reg, err := regexp.Compile(strRegFind)
	if err != nil {
		return s
	}

	return string(reg.ReplaceAll([]byte(s), []byte(new)))
}

/*
*
忽略大小写
*/
func ReplaceAll(s string, old, new string) string {
	strRegFind := fmt.Sprintf("(?i)%s", regexp.QuoteMeta(old))

	reg, err := regexp.Compile(strRegFind)
	if err != nil {
		return s
	}

	return string(reg.ReplaceAll([]byte(s), []byte(new)))
}

/*
*
不支持....
*/
func GetAreaBK(s string, start, end string, idx int) string {
	// (?<=<td>).*?(?=</td>)  // 不支持
	strRegFind := fmt.Sprintf("(?<=%s).*?(?=%s)",
		regexp.QuoteMeta(start), regexp.QuoteMeta(end))

	reg, err := regexp.Compile(strRegFind)
	if err != nil {
		return s
	}

	return reg.FindString(s)
}

/*
*

	查找s2中不存在与s1中的元素
	FindNonElement("1,2,3", "3,4,2,5") = "4,5"
*/
func FindNonElement(s1, s2 string, sep rune) string {
	rval := make([]rune, 0, len(s1))
	RangeStringSep(s2, sep, func(idx int, s string) bool {
		if !ContainElement(s1, s, sep) {
			if len(rval) > 0 {
				rval = append(rval, sep)
			}
			rval = append(rval, []rune(s)...)
		}
		return true
	})
	return string(rval)
}

/*
*

	false = ContainElement("1,2,3,16", ",", "6")
*/
func ContainElement(s string, ele string, sep rune) (rval bool) {
	RangeStringSep(s, sep, func(idx int, s1 string) bool {
		rval = s1 == ele
		return !rval
	})
	return
}

// trimq.开头的key 会去掉字符串
func ReplacePlaceholderEx(s string, start, end string, getKeyValue func(key string) (v string, ok bool)) string {
	var ok0 bool
	var replkey, id0 string
	idx := 0
	for {
		id := GetBetween(s, start, end, idx)
		if len(id) == 0 {
			break
		}

		ok0, id0 = CheckTrimPrefix(id, "trimq.")

		if v, ok := getKeyValue(id0); ok {
			if ok0 {
				replkey = fmt.Sprintf("\"%s%s%s\"", start, id, end)
			} else {
				replkey = fmt.Sprintf("%s%s%s", start, id, end)
			}

			if replkey == v { // 直接跳过，否则会造成死循环
				idx++
			} else {
				if strings.Contains(v, replkey) { // 包含了， replkey， 将会再次替换造成死循环
					idx++
				} else {
					// 注意 返回的值(v)如果继续包含replkey, 会造成死循环
					s = strings.ReplaceAll(s, replkey, v)
				}
			}
		} else {
			idx++
		}
	}
	return s
}

// 注意 getKeyValue返回的值如果继续包含replkey, 可能会造成死循环
func ReplacePlaceholder(s string, start, end string, getKeyValue func(key string) (v string, ok bool)) string {
	idx := 0
	for {
		id := GetBetween(s, start, end, idx)
		if len(id) == 0 {
			break
		}

		if v, ok := getKeyValue(id); ok {
			replkey := fmt.Sprintf("%s%s%s", start, id, end)
			if replkey == v { // 直接跳过，否则会造成死循环
				idx++
			} else {
				if strings.Contains(v, replkey) { // 包含了， replkey， 将会再次替换造成死循环
					idx++
				} else {
					// 注意 返回的值(v)如果继续包含replkey, 会造成死循环
					s = strings.ReplaceAll(s, replkey, v)
				}

			}
		} else {
			idx++
		}
	}
	return s
}

/*
`<td>a</td><td>b</td>`
GetBetween(str, "<td>", "</td>") = a

GetBetween("$now$", "$", "$") = "now"
*/
func GetBetweenEx(str string, start, end string, idx int) (ok bool, val string) {

	j := 0
	for {
		n := strings.Index(str, start)
		if n == -1 {
			return false, ""
		}
		str = string([]byte(str)[n+len(start):])
		m := strings.Index(str, end)
		if m == -1 {
			return false, ""
		}
		if j == idx {
			str = string([]byte(str)[:m])
			return true, str
		} else {
			str = string([]byte(str)[m+len(end):])
			if len(str) <= len(start) {
				return false, ""
			}
		}
		j++
	}
}

/*
`<td>a</td><td>b</td>`
GetBetween(str, "<td>", "</td>") = a

GetBetween("$now$", "$", "$") = "now"
*/
func GetBetween(str string, start, end string, idx int) string {

	j := 0
	for {
		n := strings.Index(str, start)
		if n == -1 {
			return ""
		}
		str = string([]byte(str)[n+len(start):])
		m := strings.Index(str, end)
		if m == -1 {
			return ""
		}
		if j == idx {
			str = string([]byte(str)[:m])
			return str
		} else {
			str = string([]byte(str)[m+len(end):])
			if len(str) <= len(start) {
				return ""
			}
		}
		j++
	}
}

func TryGetAsStrInValues(vals []interface{}, idx int, def string) string {
	if len(vals) <= idx {
		return def
	}
	v0 := vals[idx]
	if v0 == nil {
		return def
	}
	return GetStrValue(v0, def)
}

func IsWindows() bool {
	return runtime.GOOS == "windows"
}

func IsLinux() bool {
	return runtime.GOOS == "linux"
}

type encoding int

const (
	encodePath encoding = 1 + iota
	encodePathSegment
	encodeHost
	encodeZone
	encodeUserPassword
	encodeQueryComponent
	encodeFragment
)

type EscapeError string

func (e EscapeError) Error() string {
	return "invalid URL escape " + strconv.Quote(string(e))
}

type InvalidHostError string

func (e InvalidHostError) Error() string {
	return "invalid character " + strconv.Quote(string(e)) + " in host name"
}

const upperhex = "0123456789ABCDEF"

func ishex(c byte) bool {
	switch {
	case '0' <= c && c <= '9':
		return true
	case 'a' <= c && c <= 'f':
		return true
	case 'A' <= c && c <= 'F':
		return true
	}
	return false
}

func unhex(c byte) byte {
	switch {
	case '0' <= c && c <= '9':
		return c - '0'
	case 'a' <= c && c <= 'f':
		return c - 'a' + 10
	case 'A' <= c && c <= 'F':
		return c - 'A' + 10
	}
	return 0
}

// Return true if the specified character should be escaped when
// appearing in a URL string, according to RFC 3986.
//
// Please be informed that for now shouldEscape does not check all
// reserved characters correctly. See golang.org/issue/5684.
func shouldEscape(c byte, mode encoding) bool {
	// §2.3 Unreserved characters (alphanum)
	if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
		return false
	}

	if mode == encodeHost || mode == encodeZone {
		// §3.2.2 Host allows
		//	sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
		// as part of reg-name.
		// We add : because we include :port as part of host.
		// We add [ ] because we include [ipv6]:port as part of host.
		// We add < > because they're the only characters left that
		// we could possibly allow, and Parse will reject them if we
		// escape them (because hosts can't use %-encoding for
		// ASCII bytes).
		switch c {
		case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '[', ']', '<', '>', '"':
			return false
		}
	}

	switch c {
	case '-', '_', '.', '~': // §2.3 Unreserved characters (mark)
		return false

	case '$', '&', '+', ',', '/', ':', ';', '=', '?', '@': // §2.2 Reserved characters (reserved)
		// Different sections of the URL allow a few of
		// the reserved characters to appear unescaped.
		switch mode {
		case encodePath: // §3.3
			// The RFC allows : @ & = + $ but saves / ; , for assigning
			// meaning to individual path segments. This package
			// only manipulates the path as a whole, so we allow those
			// last three as well. That leaves only ? to escape.
			return c == '?'

		case encodePathSegment: // §3.3
			// The RFC allows : @ & = + $ but saves / ; , for assigning
			// meaning to individual path segments.
			return c == '/' || c == ';' || c == ',' || c == '?'

		case encodeUserPassword: // §3.2.1
			// The RFC allows ';', ':', '&', '=', '+', '$', and ',' in
			// userinfo, so we must escape only '@', '/', and '?'.
			// The parsing of userinfo treats ':' as special so we must escape
			// that too.
			return c == '@' || c == '/' || c == '?' || c == ':'

		case encodeQueryComponent: // §3.4
			// The RFC reserves (so we must escape) everything.
			return true

		case encodeFragment: // §4.1
			// The RFC text is silent but the grammar allows
			// everything, so escape nothing.
			return false
		}
	}

	if mode == encodeFragment {
		// RFC 3986 §2.2 allows not escaping sub-delims. A subset of sub-delims are
		// included in reserved from RFC 2396 §2.2. The remaining sub-delims do not
		// need to be escaped. To minimize potential breakage, we apply two restrictions:
		// (1) we always escape sub-delims outside of the fragment, and (2) we always
		// escape single quote to avoid breaking callers that had previously assumed that
		// single quotes would be escaped. See issue #19917.
		switch c {
		case '!', '(', ')', '*':
			return false
		}
	}

	// Everything else must be escaped.
	return true
}

// QueryUnescape does the inverse transformation of QueryEscape,
// converting each 3-byte encoded substring of the form "%AB" into the
// hex-decoded byte 0xAB.
// It returns an error if any % is not followed by two hexadecimal
// digits.
func QueryUnescape(s string) (string, error) {
	return unescape(s, encodeQueryComponent)
}

// PathUnescape does the inverse transformation of PathEscape,
// converting each 3-byte encoded substring of the form "%AB" into the
// hex-decoded byte 0xAB. It returns an error if any % is not followed
// by two hexadecimal digits.
//
// PathUnescape is identical to QueryUnescape except that it does not
// unescape '+' to ' ' (space).
func PathUnescape(s string) (string, error) {
	return unescape(s, encodePathSegment)
}

// unescape unescapes a string; the mode specifies
// which section of the URL string is being unescaped.
func unescape(s string, mode encoding) (string, error) {
	// Count %, check that they're well-formed.
	n := 0
	hasPlus := false
	for i := 0; i < len(s); {
		switch s[i] {
		case '%':
			n++
			if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
				s = s[i:]
				if len(s) > 3 {
					s = s[:3]
				}
				return "", EscapeError(s)
			}
			// Per https://tools.ietf.org/html/rfc3986#page-21
			// in the host component %-encoding can only be used
			// for non-ASCII bytes.
			// But https://tools.ietf.org/html/rfc6874#section-2
			// introduces %25 being allowed to escape a percent sign
			// in IPv6 scoped-address literals. Yay.
			if mode == encodeHost && unhex(s[i+1]) < 8 && s[i:i+3] != "%25" {
				return "", EscapeError(s[i : i+3])
			}
			if mode == encodeZone {
				// RFC 6874 says basically "anything goes" for zone identifiers
				// and that even non-ASCII can be redundantly escaped,
				// but it seems prudent to restrict %-escaped bytes here to those
				// that are valid host name bytes in their unescaped form.
				// That is, you can use escaping in the zone identifier but not
				// to introduce bytes you couldn't just write directly.
				// But Windows puts spaces here! Yay.
				v := unhex(s[i+1])<<4 | unhex(s[i+2])
				if s[i:i+3] != "%25" && v != ' ' && shouldEscape(v, encodeHost) {
					return "", EscapeError(s[i : i+3])
				}
			}
			i += 3
		case '+':
			hasPlus = mode == encodeQueryComponent
			i++
		default:
			if (mode == encodeHost || mode == encodeZone) && s[i] < 0x80 && shouldEscape(s[i], mode) {
				return "", InvalidHostError(s[i : i+1])
			}
			i++
		}
	}

	if n == 0 && !hasPlus {
		return s, nil
	}

	var t strings.Builder
	t.Grow(len(s) - 2*n)
	for i := 0; i < len(s); i++ {
		switch s[i] {
		case '%':
			t.WriteByte(unhex(s[i+1])<<4 | unhex(s[i+2]))
			i += 2
		case '+':
			if mode == encodeQueryComponent {
				t.WriteByte(' ')
			} else {
				t.WriteByte('+')
			}
		default:
			t.WriteByte(s[i])
		}
	}
	return t.String(), nil
}

// QueryEscape escapes the string so it can be safely placed
// inside a URL query.
func QueryEscape(s string) string {
	return escape(s, encodeQueryComponent)
}

// PathEscape escapes the string so it can be safely placed inside a URL path segment,
// replacing special characters (including /) with %XX sequences as needed.
func PathEscape(s string) string {
	return escape(s, encodePathSegment)
}

func escape(s string, mode encoding) string {
	spaceCount, hexCount := 0, 0
	for i := 0; i < len(s); i++ {
		c := s[i]
		if shouldEscape(c, mode) {
			if c == ' ' && mode == encodeQueryComponent {
				spaceCount++
			} else {
				hexCount++
			}
		}
	}

	if spaceCount == 0 && hexCount == 0 {
		return s
	}

	var buf [64]byte
	var t []byte

	required := len(s) + 2*hexCount
	if required <= len(buf) {
		t = buf[:required]
	} else {
		t = make([]byte, required)
	}

	if hexCount == 0 {
		copy(t, s)
		for i := 0; i < len(s); i++ {
			if s[i] == ' ' {
				t[i] = '+'
			}
		}
		return string(t)
	}

	j := 0
	for i := 0; i < len(s); i++ {
		switch c := s[i]; {
		case c == ' ' && mode == encodeQueryComponent:
			t[j] = '+'
			j++
		case shouldEscape(c, mode):
			t[j] = '%'
			t[j+1] = upperhex[c>>4]
			t[j+2] = upperhex[c&15]
			j += 3
		default:
			t[j] = s[i]
			j++
		}
	}
	return string(t)
}

type StrMap map[string]string

func NewStrMap() StrMap {
	return make(StrMap)
}

func NewStrMapFromURLStr(s string) StrMap {
	strmap := NewStrMap()
	strmap.URLFormDecode(s)
	return strmap
}

func NewStrMapEx(s, kvsep, itmsep string) StrMap {
	r := make(StrMap)
	r.ParseKVPairs(s, kvsep, itmsep)
	return r
}

func (this StrMap) Reset() {
	for k := range this {
		delete(this, k)
	}
}

// ExecReplace 利用映射关系进行替换， key -> value
func (this StrMap) ExecReplace(s string) string {
	for k, v := range this {
		s = ReplaceAll(s, k, v)
	}
	return s
}

func (this StrMap) SortRange(fn func(k, v string) bool) {
	if this == nil {
		return
	}
	keys := make([]string, 0, len(this))
	for k := range this {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		v := this[k]
		if !fn(k, v) {
			break
		}
	}
}

func (this StrMap) SortRangeEncode(kvspliter string, itmspliter string, fn func(k, v string) bool) string {
	if this == nil {
		return ""
	}
	var buf strings.Builder
	this.SortRange(func(k, v string) bool {
		if fn(k, v) {
			if buf.Len() > 0 {
				buf.WriteString(itmspliter)
			}
			buf.WriteString(k)
			buf.WriteString(kvspliter)
			buf.WriteString(v)
		}
		return true
	})
	return buf.String()

}

func (this StrMap) Encode(kvspliter string, itmspliter string) string {
	if this == nil {
		return ""
	}
	var buf strings.Builder
	keys := make([]string, 0, len(this))
	for k := range this {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		if buf.Len() > 0 {
			buf.WriteString(itmspliter)
		}
		v := this[k]
		buf.WriteString(k)
		buf.WriteString(kvspliter)
		buf.WriteString(v)
	}
	return buf.String()
}

func MapEncode(strMap map[string]string, kvsep, itmsep string, escapeflag bool, bb io.Writer) {
	keys := make([]string, 0, len(strMap))
	for k := range strMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	i := 0
	for _, k := range keys {
		v := strMap[k]
		if i > 0 {
			bb.Write([]byte(itmsep))
		}
		if escapeflag {
			keyEscaped := QueryEscape(k)
			bb.Write([]byte(keyEscaped))
			bb.Write([]byte(kvsep))
			bb.Write([]byte(QueryEscape(v)))
		} else {
			bb.Write([]byte(k))
			bb.Write([]byte(kvsep))
			bb.Write([]byte(v))
		}
		i++
	}
}

func (this StrMap) DeleteByKeylst(keylst ...string) (r int) {
	for _, k := range keylst {
		delete(this, k)
		r++
	}
	return
}

func (this StrMap) SortRangeEncodeEx(kvspliter string, itmspliter string, fn func(k, v string) (k1, v1 string, ok bool)) string {
	if this == nil {
		return ""
	}
	var buf strings.Builder
	kvlst := make([][]string, 0, len(this))
	for k, v := range this {
		if k1, v1, ok := fn(k, v); ok {
			kvlst = append(kvlst, []string{k1, v1})
		}
	}
	sort.Slice(kvlst, func(i, j int) bool {
		return kvlst[i][0] < kvlst[j][0]
	})

	for _, kv := range kvlst {
		if buf.Len() > 0 {
			buf.WriteString(itmspliter)
		}
		buf.WriteString(kv[0])
		buf.WriteString(kvspliter)
		buf.WriteString(kv[1])
	}
	return buf.String()
}

func (this StrMap) SortRangeUrlEncode(fn func(k, v string) bool) string {
	return this.SortRangeEncodeEx("=", "&", func(k, v string) (k1, v1 string, ok bool) {
		ok = fn(k, v)
		if ok {
			k1 = QueryEscape(k)
			v1 = QueryEscape(v)
		}
		return
	})
}

func (this StrMap) SortRangeUrlEncode0(fn func(k, v string) bool) string {
	return this.SortRangeEncodeEx("=", "&", func(k, v string) (k1, v1 string, ok bool) {
		ok = fn(k, v)
		if ok {
			k1 = UrlEncode0(k)
			v1 = UrlEncode0(v)
		}
		return
	})
}

func (this StrMap) URLFormEncodeKeylst(keylst ...string) string {
	var sb strings.Builder
	for _, k := range keylst {
		if v, ok := this[k]; ok {
			if sb.Len() > 0 {
				sb.WriteByte('&')
			}
			keyEscaped := QueryEscape(k)
			sb.WriteString(keyEscaped)
			sb.WriteByte('=')
			sb.WriteString(QueryEscape(v))
		}
	}
	return sb.String()
}

// 最简单的方式进行编码
func (this StrMap) URLEncode0WithKeys(keylst ...string) string {
	if this == nil {
		return ""
	}
	var buf strings.Builder
	for _, k := range keylst {
		if v, ok := this[k]; ok {
			if buf.Len() > 0 {
				buf.WriteByte('&')
			}
			urlEncode0(&buf, k)
			buf.WriteByte('=')
			urlEncode0(&buf, v)
		}
	}
	return buf.String()
}

// 前缀或者后缀
type PartString string

func (this PartString) UrlEncodeTryTrimPrefix(k, v string) (k1, v1 string, ok bool) {
	k1, ok = TryTrimPrefix(k, string(this))
	if ok {
		k1 = UrlEncode0(k1)
		v1 = UrlEncode0(v)
	}
	return
}

func (this PartString) UrlEncodeTryPrefix(k, v string) (k1, v1 string, ok bool) {
	ok = strings.HasPrefix(k, string(this))
	if ok {
		k1 = UrlEncode0(k)
		v1 = UrlEncode0(v)
	}
	return
}

func (this PartString) UrlEncodeTryTrimSuffix(k, v string) (k1, v1 string, ok bool) {
	k1, ok = TryTrimSuffix(k, string(this))
	if ok {
		k1 = UrlEncode0(k1)
		v1 = UrlEncode0(v)
	}
	return
}

func (this PartString) UrlEncodeTrySuffix(k, v string) (k1, v1 string, ok bool) {
	ok = strings.HasSuffix(k, string(this))
	if ok {
		k1 = UrlEncode0(k)
		v1 = UrlEncode0(v)
	}
	return
}

func (this StrMap) URLEncode0Prefix(prefix string, trimPrefix bool) string {
	if trimPrefix {
		return this.SortRangeEncodeEx("=", "&", PartString(prefix).UrlEncodeTryTrimPrefix)
	} else {
		return this.SortRangeEncodeEx("=", "&", PartString(prefix).UrlEncodeTryPrefix)
	}
}

func (this StrMap) URLEncode0Suffix(prefix string, trimPrefix bool) string {
	if trimPrefix {
		return this.SortRangeEncodeEx("=", "&", PartString(prefix).UrlEncodeTryTrimSuffix)
	} else {
		return this.SortRangeEncodeEx("=", "&", PartString(prefix).UrlEncodeTrySuffix)
	}
}

// 最简单的方式进行编码
func (this StrMap) URLEncode0() string {
	if this == nil {
		return ""
	}
	var buf strings.Builder
	keys := make([]string, 0, len(this))
	for k := range this {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		v := this[k]
		if buf.Len() > 0 {
			buf.WriteByte('&')
		}
		urlEncode0(&buf, k)
		buf.WriteByte('=')
		urlEncode0(&buf, v)
	}
	return buf.String()
}

func (this StrMap) URLFormEncode() string {
	if this == nil {
		return ""
	}
	var buf strings.Builder
	keys := make([]string, 0, len(this))
	for k := range this {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		v := this[k]
		keyEscaped := QueryEscape(k)
		if buf.Len() > 0 {
			buf.WriteByte('&')
		}
		buf.WriteString(keyEscaped)
		buf.WriteByte('=')
		buf.WriteString(QueryEscape(v))
	}
	return buf.String()
}

func (this StrMap) URLFormDecode(s string) {
	lst := strings.Split(s, "&")
	if len(lst) == 0 {
		return
	}
	for i := 0; i < len(lst); i++ {
		k, v := Split2Str(lst[i], "=")
		k, _ = QueryUnescape(k)
		v, _ = QueryUnescape(v)
		if len(k) > 0 {
			this[k] = v
		}
	}
}

func (this StrMap) CopyFrom(src StrMap) {
	for k, v := range src {
		this[k] = v
	}
}

// 覆盖掉前一个值
func (this StrMap) CopyFromPrefix(src StrMap, prefix string, overrideFlag bool) {
	for k, v := range src {
		if k1, ok := TryTrimPrefix(k, prefix); ok {
			if overrideFlag {
				this[k1] = v
			} else {
				if _, ok1 := this[k1]; !ok1 {
					this[k1] = v
				}
			}
		}
	}
}

func (this StrMap) ParseKVPairsEx(s string, kvsep string, itmsep string, keylower bool) {
	lst := strings.Split(s, itmsep)
	if len(lst) == 0 {
		return
	}

	for i := 0; i < len(lst); i++ {
		k, v := Split2Str(lst[i], kvsep)
		if len(k) > 0 {
			if keylower {
				k = strings.ToLower(k)
			}
			this[k] = v
		}
	}
}

func (this StrMap) ParseKVPairs(s string, kvsep string, itmsep string) {
	lst := strings.Split(s, itmsep)
	if len(lst) == 0 {
		return
	}

	for i := 0; i < len(lst); i++ {
		k, v := Split2Str(lst[i], kvsep)
		k = Trim(k)
		if len(k) > 0 {
			this[k] = v
		}
	}
}

func (this StrMap) StringByName(k string, def string) string {
	if v, ok := this[k]; ok {
		return v
	} else {
		return def
	}
}

func (this StrMap) IntByName(k string, def int) int {
	if v, ok := this[k]; ok {
		if len(v) == 0 {
			return def
		}
		return StrToIntDef(v, def)
	} else {
		return def
	}
}

func (this StrMap) Float64ByName(k string, def float64) float64 {
	if v, ok := this[k]; ok {
		return StrToFloat64Def(v, def)
	} else {
		return def
	}
}

func (this StrMap) U8ByName(k string, def byte) byte {
	return byte(this.IntByName(k, int(def)))
}

func (this StrMap) Int8ByName(k string, def int8) int8 {
	return int8(this.IntByName(k, int(def)))
}

func (this StrMap) Int16ByName(k string, def int16) int16 {
	return int16(this.IntByName(k, int(def)))
}

func (this StrMap) UnixTimeByName(k string, def time.Time) time.Time {
	v := this.IntByName(k, -99999)
	if v == -99999 {
		return def
	} else {
		return time.Unix(int64(v), 0)
	}
}

/*
解析命令行
XX.exe -a=v
*/
func (this StrMap) ParseCmdArgs(args []string) {
	for i := 0; i < len(args); i++ {
		s1, s2 := Split2Str(args[i], "=")

		if len(s1) > 0 {
			if s1[0] == '-' {
				s1 = s1[1:]
			}
			if len(s2) == 0 {
				s2 = s1
				if i == 0 {
					this["0"] = s1
				} else {
					this[s1] = s2
				}
			} else {
				_, s2 = CheckTrimQuoteChr(s2, QUOTECHR, QUOTECHR)
				this[s1] = s2
			}
		}
	}
}

func EscapeChar(c byte) byte {
	switch c {
	case 't':
		return '\t'
	default:
		return c
	}
}

// $1 spidx   ' ' 3, tokens[2] = " "
func ParseTokens(s string, sep byte) (tokens []string) {

	var eMarker byte = 0
	var tmp bytes.Buffer
	var slashFlag bool

	var nextFunc func(c byte)

	var nextForQuote = func(c byte) {
		if c == eMarker {
			tokens = append(tokens, tmp.String())
			tmp.Reset()
			nextFunc = nil
		} else {
			tmp.WriteByte(c)
		}
		return
	}

	for i := 0; i < len(s); {
		c := s[i]

		if slashFlag {
			tmp.WriteByte(EscapeChar(c))
			i++
			slashFlag = false
			continue
		}

		if c == CHAR_SLASH {
			slashFlag = true
			i++
			continue
		}

		if nextFunc != nil {
			nextFunc(c)
			i++
			continue
		}

		switch c {
		case sep:
			if tmp.Len() > 0 {
				tokens = append(tokens, tmp.String())
				tmp.Reset()
			}
			i++
			continue
		case CHAR_QUOTE_DOUBLE:
			eMarker = CHAR_QUOTE_DOUBLE
			nextFunc = nextForQuote
			i++
			continue
		case CHAR_QUOTE_SINGLE:
			eMarker = CHAR_QUOTE_SINGLE
			nextFunc = nextForQuote
			i++
			continue
		default:
			tmp.WriteByte(c)
			i++
		}
	}

	if tmp.Len() > 0 {
		tokens = append(tokens, tmp.String())
	}
	return
}

func Map2StringList(lst map[string]struct{}) []string {
	rval := make([]string, 0, len(lst))
	for k, _ := range lst {
		rval = append(rval, k)
	}

	sort.Slice(rval, func(i, j int) bool {
		return rval[i] < rval[j]
	})
	return rval
}

func CompareStringList(a []string, b []string) bool {
	if len(a) != len(b) {
		return false
	}

	for i := 0; i < len(a); i++ {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}

func SplitLabels(s string, sep string, trimPrefix, trimSuffix string, skipEmpty bool) (labels []string) {
	if len(s) == 0 {
		return nil
	}
	strs := strings.Split(s, sep)
	for _, str := range strs {
		str, _ = TryTrimPrefix(str, trimPrefix)
		str, _ = TryTrimSuffix(str, trimSuffix)
		if len(str) > 0 || !skipEmpty {
			labels = append(labels, str)
		}

	}
	return labels
}

func SplitString(s string, sep string, skipEmpty bool) (strlst []string) {
	s = Trim(s)
	if len(s) == 0 {
		return nil
	}
	strs := strings.Split(s, sep)
	if skipEmpty {
		strs = DeleteEmpty(strs)
	}

	return strs
}

func JoinMap[K Ordered, V Ordered](mp map[K]V, sep string, joinFn func(k K, v V) string) string {
	type kv struct {
		k K
		v V
	}
	var lst = make([]*kv, 0, len(mp))
	for k, v := range mp {
		lst = append(lst, &kv{k: k, v: v})
	}
	sort.Slice(lst, func(i, j int) bool {
		return lst[i].k < lst[j].k
	})
	if joinFn == nil {
		joinFn = func(k K, v V) string {
			return fmt.Sprintf("%v%s%v", k, "=", v)
		}
	}
	var sb strings.Builder
	for _, itm := range lst {
		if sb.Len() > 0 {
			sb.WriteString(sep)
		}
		sb.WriteString(joinFn(itm.k, itm.v))
	}
	return sb.String()
}
